####################################################-*- coding: utf-8 -*-#####
#
#
# log class, thread safe, singleton
# TODO: provide more power print like print(*arg1, **arg2)
# 
#
##############################################################################
import os
from threading import Thread, Lock, Event
from datetime import datetime
import configparser
import utils

class Log(Thread, BaseException):
    __single = None
    def __init__(self):
        if Log.__single:
            raise Log.__single
        
        Thread.__init__(self)
        filename = 'log.txt'
        Log.__single = self
        fullname  = utils.getRootDir() + os.sep + filename
        self.running = True
        self.lock = Lock()
        self.signal = Event()
        self.fs   = open(fullname, 'a+')
        self.queue = []

    def __del__(self):
        self.fs.close()

    @classmethod
    def getInstance(cls):
        """Static method to return the object of the class"""
        try:
            single = cls()
        except cls as s:
            single = s
        return single

    def exit(self):
        # FIXME: busy wait
        while len(self.queue):
            time.sleep(1)
        
        self.signal.set()       # signal the empty wait if exists
        self.running = False
    
    def run(self):
        """ flush local log buffer list to log file intervally."""
        empty = False
        while self.running:
            self.lock.acquire()
            if len(self.queue) == 0:
                empty = True
            else:
                empty = False
                msg = self.queue.pop()
            self.lock.release()

            if empty:
                self.signal.wait()
                self.signal.clear() # Don't forget clear
            else:
                self.fs.write('%s\n'%msg)

        self.fs.write('[%s][log] end of file\n'%datetime.now())
        self.fs.flush()         # Only flush at the end
        
    def write(self, module, msg):
        """Write log into a thread local log buffer list."""
        with self.lock:         # equals lock.acquire() and lock.release()
            now = datetime.now()
            log = '[%s][%s] %s'%(now, module, msg)
            self.queue.append(log)
            self.signal.set()
